package grupo1.fotomultas.Fotomultas;

import grupo1.fotomultas.Fotomultas.Categorias.Categoria;
import grupo1.fotomultas.Fotomultas.EstadosInfraccion.InfraccionPerdonada;
import grupo1.fotomultas.Fotomultas.Infracciones.Infraccion;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.uqbar.commons.model.UserException;

public class Vehiculo {
	
	private static final int MAX_CANTIDAD_PUNTOS = 20;	
	private final String patente;
	private Set<Categoria> categorias; 
	private Set<Infraccion> infracciones;
	
	public Vehiculo(String patente){
		this.categorias = new HashSet<Categoria>();
		this.infracciones = new HashSet<Infraccion>();
		this.patente = patente;
		HomeVehiculos.Instance().agregarVehiculo(this);
	}

	public void agregarInfraccion(Infraccion infraccion){
		if(this.getInfracciones().contains(infraccion))
			throw new UserException("Error, quieren insertar 2da multa igual a una existente");

		System.out.println(this.getPatente());
		System.out.println("Se agrego una infraccion Vehiculo: "+ this.getPatente() + " " + infraccion.getTipoInfraccion().toString());
		System.out.println("Puntos: "+ infraccion.getPuntos() +" Costo: " +infraccion.getCosto());

		this.getInfracciones().add(infraccion);
		infraccion.setVehiculo(this);
		this.seAgregoUnaInfraccion(infraccion);
	}

	public void quitarInfraccion(Infraccion infraccion) {
		if (this.getInfracciones().contains(infraccion)) {
			this.getInfracciones().remove(infraccion);
			this.verificarCategoriasExistentes();
		}
	}

	private void seAgregoUnaInfraccion(Infraccion infraccion) {
		this.notificar(infraccion);
		this.actualizarCategorias();
		
	}

	private void notificar(Infraccion infraccion) {
		for(Categoria categoria : categorias){
			categoria.notificar(infraccion);
		}
	}

	public void actualizarCategorias() {
		Categoria.actualizarCategoriasParaVehiculo(this);
	}

	public void verificarCategoriasExistentes() {
		Categoria.actualizarCategoriasExistentesParaVehiculo(this);
		
	}
	
	public void setInfracciones(Set<Infraccion> infracciones) {
		this.infracciones = infracciones;
	}

	public Set<Infraccion> getInfracciones() {
		return infracciones;
	}

	public void setCategorias(Set<Categoria> categorias) {
		this.categorias = categorias;
	}

	public Set<Categoria> getCategorias() {
		return categorias;
	}

	public void agregarCategoria(Categoria categoria) {
		if(!categorias.contains(categoria)){
			System.out.println("Se agrego una Categoria al Vehiculo: "+ getPatente() + " Categoria Agregada:" + categoria.toString());
			categorias.add(categoria);
		}	
	}

	public double totalDineroAdeudado() {
		double totalMultas = 0;

		for (Infraccion infraccion : infracciones)
			totalMultas += infraccion.getCosto();

		return totalMultas;
	}

	public int puntosDisponibles() {
		int totalPuntosPerdidos = 0;
		for (Infraccion infraccion : infracciones){
			if(!infraccion.isPuntosPerdonados())
				totalPuntosPerdidos =+ infraccion.getPuntos();	
		}
		return getPuntosMax() - totalPuntosPerdidos;
	}

	public int cantidadDeInfracciones() {
		return this.getInfracciones().size();
	}

	static public int getPuntosMax() {
		return MAX_CANTIDAD_PUNTOS;
	}

	public String getPatente() {
		return patente;
	}
	
	public void pagarInfracciones(Set<Infraccion> infracciones){
		for (Infraccion infraccion : infracciones)
			this.pagarInfraccion(infraccion);
		
	}

	private void pagarInfraccion(Infraccion infraccion) {
		infraccion.infraccionPaga();		
	}

	public void removerCategoria(Categoria unaCategoria) {
		this.categorias.remove(unaCategoria);
		
	}

	public Infraccion obtenerUltimaInfraccion() {
		List<Infraccion> listaInfracciones = this.ordenarInfraccionesPor(InfraccionSort.dateDescComparator());
		return (this.obtenerPrimerElemento(listaInfracciones));
		
	}

	private Infraccion obtenerPrimerElemento(List<Infraccion> listaInfracciones) {
		if (listaInfracciones != null && listaInfracciones.size() >= 1) {
			return listaInfracciones.iterator().next();
		   }	
		return null;
	}

	private List<Infraccion> ordenarInfraccionesPor(Comparator<Infraccion> criterioOrden) {
		List<Infraccion> listaInfracciones = new ArrayList<Infraccion>(infracciones);
		
		Collections.sort(listaInfracciones, criterioOrden);
		return listaInfracciones;
	}

	public void recuperaPuntos() {
		for (Infraccion unaInfraccion : infracciones)
			unaInfraccion.setPuntosPerdonados(true);
	}

	public void verificarInfraccionesPerdonadas() {
		List<Infraccion> listaInfracciones = this.ordenarInfraccionesPor(InfraccionSort.dateAscComparator());
		Infraccion infraccionAnterior = null;
		
		// Recorro las infracciones y si la fecha entre infracciones es mayor al anho las perdono
		for (Infraccion infraccion : listaInfracciones) {
			Calendar fecha = new GregorianCalendar(infraccion.getFecha().get(Calendar.YEAR) - 1,
													infraccion.getFecha().get(Calendar.MONTH),
													infraccion.getFecha().get(Calendar.DATE));

			if (infraccionAnterior == null || infraccionAnterior.getFecha().before(fecha)) {
				infraccion.setEstado(InfraccionPerdonada.instance());
				infraccionAnterior = infraccion;
			} 
		}
	}
		
}

